package com.jh.netty.ws;

import com.jh.netty.instruction.CommunicationPacket;
import com.jh.netty.server.ChannelSupervise;
import com.jh.netty.util.ConvertCode;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.websocketx.*;
import io.netty.util.CharsetUtil;

import static io.netty.handler.codec.http.HttpUtil.isKeepAlive;


public class WebSocketHandler extends SimpleChannelInboundHandler<Object> {

    // onmsg
    // 有信号进来时
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
//        System.out.println("websocket消息 = " + msg);
//        System.out.println("websocket消息: " + msg.toString());

//        handWsMessage(ctx, msg);

//        ChannelSupervise.findChannel(incoming.id().asShortText());
//        for (Channel channel : channels) {
//            System.out.println("ip = " + channel.remoteAddress().toString());
//
//            if (channel != incoming) { //排除当前通道
//                String str = String.format("[%s]说: %s\n", incoming.remoteAddress().toString().substring(1), s);
//                channel.writeAndFlush(str);
//            }
//        }

        if (msg instanceof FullHttpRequest) {
            FullHttpRequest http = (FullHttpRequest) msg;
            System.out.println("http uri = " + http.uri());
            System.out.println("http method = " + http.method());
//            System.out.println("http消息: " + msg.toString());
            handHttpRequest(ctx, http);
        } else if (msg instanceof WebSocketFrame) {
            WebSocketFrame wsf = (WebSocketFrame) msg;
            handWsMessage(ctx, wsf);
        } else {
            System.out.println("其他消息");
            ctx.channel().writeAndFlush(new TextWebSocketFrame("服务器连接成功！接收到其他消息"));
        }
    }

    // onerror
    // 发生异常时
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        Channel incoming = ctx.channel();
        System.out.println("[Server]:" + incoming.remoteAddress().toString().substring(1) + "异常");
        ctx.close();
    }

    /**
     *  集中处理 ws 中的消息
     * @param ctx
     * @param msg webSocket 消息
     */
    private void handWsMessage(ChannelHandlerContext ctx, WebSocketFrame msg) {
//        System.out.println("========" + msg.toString());
//        System.out.println("========" + ByteBufUtil.hexDump(msg.content()));

        if (msg instanceof CloseWebSocketFrame) {
            // 关闭指令
            CloseWebSocketFrame cws = (CloseWebSocketFrame) msg;
//            handshaker.close(ctx.channel(), (CloseWebSocketFrame) msg.retain());
            System.out.println("关闭指令 = " + cws.reasonText());
            ctx.channel().write(cws);
            return;
        }

        if (msg instanceof PingWebSocketFrame) {
            // ping 消息
            ctx.channel().write(new PongWebSocketFrame(msg.content().retain()));
            return;
        }

        if (msg instanceof TextWebSocketFrame) {
            TextWebSocketFrame message = (TextWebSocketFrame) msg;
            String ins = message.text();
//            System.out.println("websocket 文本消息 = " + ins);
            ctx.channel().writeAndFlush( new TextWebSocketFrame("接收到的消息：[" + ins + "]"));
//            CommunicationPacket cp = CommunicationPacket.parse(ins);
//            if (cp.isValidCRC16()) {
//
////                ByteBuf bb = Unpooled.buffer();
////                bb.writeBytes(ConvertCode.hexString2Bytes(ins));
//                ChannelSupervise.send(cp.toByteBuf());
//            }
            // 文本消息
//            WsMessage wsMessage = gson.fromJson(message.text(), WsMessage.class);
//            logger.info("接收到消息：" + wsMessage);
//            switch (wsMessage.getT()){
//                case 1: // 进入房间
//                    // 给进入的房间的用户响应一个欢迎消息，向其他用户广播一个有人进来的消息
//                    broadcastWsMsg( ctx, new WsMessage(-10001,wsMessage.getN()) );
//                    AttributeKey<String> name = AttributeKey.newInstance(wsMessage.getN());
//                    ctx.channel().attr(name);
//                    ctx.channel().writeAndFlush( new TextWebSocketFrame(
//                        gson.toJson(new WsMessage(-1, wsMessage.getN()))));
//                    break;
//
//                case 2: // 发送消息
//                    // 广播消息
//                    broadcastWsMsg( ctx, new WsMessage(-2, wsMessage.getN(), wsMessage.getBody()) );
//                    break;
//                case 3: // 离开房间.
//                    broadcastWsMsg( ctx, new WsMessage(-11000, wsMessage.getN(), wsMessage.getBody()) );
//                    break;
//            }
        }

        // donothing, 暂时不处理二进制消息
    }

    // 处理 http 请求，WebSocket 初始握手 (opening handshake ) 都始于一个 HTTP 请求
    private void handHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) {
        // 回复消息
        ctx.channel().writeAndFlush(new TextWebSocketFrame("这是个 http 请求！"));

//        if (!req.decoderResult().isSuccess() || !("websocket".equals(req.headers().get("Upgrade")))) {
//            sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
//                    HttpResponseStatus.BAD_REQUEST));
//            return;
//        }

//        WebSocketServerHandshakerFactory factory = new WebSocketServerHandshakerFactory("ws://"
//            + NettyConfig.WS_HOST + NettyConfig.WS_PORT, null, false);
//        handshaker = factory.newHandshaker(req);
//        if(handshaker == null){
//            WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());
//        } else {
//            handshaker.handshake(ctx.channel(), req);
//        }
    }

    // 响应非 WebSocket 初始握手请求
    private void sendHttpResponse(ChannelHandlerContext ctx, FullHttpRequest req, DefaultFullHttpResponse res) {
        if (res.status().code() != 200) {
            ByteBuf buf = Unpooled.copiedBuffer(res.status().toString(), CharsetUtil.UTF_8);
            res.content().writeBytes(buf);
            buf.release();
        }
        ChannelFuture f = ctx.channel().writeAndFlush(res);
        // 如果是非Keep-Alive，关闭连接
        if (!isKeepAlive(req) || res.status().code() != 200) {
            f.addListener(ChannelFutureListener.CLOSE);
        }
    }

//    // 广播 websocket 消息（不给自己发）
//    private void broadcastWsMsg(ChannelHandlerContext ctx, WsMessage msg) {
////        NettyConfig.group.stream()
////                .filter(channel -> channel.id() != ctx.channel().id())
////                .forEach(channel -> {
////                    channel.writeAndFlush( new TextWebSocketFrame( gson.toJson( msg )));
////                });
//    }
}